10869. Строительная
конструкция
Заданы n зданий с высотами
h1, h2, …, hn.
Ваша цель — сделать все здания одной высоты. Это можно сделать, удалив кирпичи
из здания или добавив в него несколько кирпичей. Удаление или добавление
кирпича производится за определенную плату, которая будет указана вместе с
высотой зданий. Найдите минимальную стоимость, за которую можно сделать здания
красивыми, реконструировав здания так, чтобы n зданий удовлетворяли
условию h1 = h2 = ... = hn = k (k может быть
любым целым неотрицательным числом).
Для удобства все постройки
представляют собой вертикальные сваи из кирпича, которые имеют одинаковые
размеры.
Вход. Первая строка содержит количество
зданий n (n ≤
105). Вторая строка содержит n целых чисел – высоты зданий h1,
h2, …, hn (0 ≤ hi ≤ 104). Третья строка содержит n
целых чисел c1, c2, ..., cn
(0 ≤ ci ≤ 104) – стоимость добавления или удаления
кирпича из соответствующего здания.
Выход. Выведите минимальную стоимость,
за которую можно сделать все постройки красивыми.
Пример
входа 1 |
Пример
выхода 1 |
4 2 3 1 4 10 20 30 40 |
110 |
|
|
Пример
входа 2 |
Пример
выхода 2 |
3 1 2 3 10 100 1000 |
120 |
тернарный
поиск
Отсортируем здания по высоте так, чтобы h1 ≤ h2 ≤
…≤ hn. Здания с одинаковыми высотами сортируем по возрастанию
стоимости добавления / удаления.
Найдем стоимость, за которую
можно высоту всех домов сделать равной hx (1 ≤
x ≤ n). Она равна
Функция f(x) вогнутая и имеет глобальный минимум, который ищется тернарным
поиском.
Пример
Рассмотрим первый пример. Отсортируем здания по высотам:
Найдем значение функции f(x) для всех значений высот:
·
f(1) = (1 – 1) * 30 + (2 – 1) * 10 + (3 – 1) * 20 + (4 – 1) * 40
= 170,
·
f(2) = (2 – 1) * 30 + (2 – 2) * 10 + (3 – 2) * 20
+ (4 – 2) * 40 = 130,
·
f(3) = (3 – 1) * 30 + (3 – 2) * 10 + (3 – 3) * 20
+ (4 – 3) * 40 = 110,
·
f(4) = (4 – 1) * 30 + (4 – 2) * 10 + (4 – 3) * 20 + (4 – 4) * 40
= 130
Минимум функции f(x) достигается при x = 3, при этом f(3) = 110.
Реализация алгоритма
Каждое здание имеет высоту h
и стоимость cost добавления / удаления этажа. Информацию о зданиях храним в массиве b.
#define MAX 100001
struct Building
{
int h, cost;
};
Building b[MAX];
Функция cmp является компаратором для сортировки
зданий. Здания сортируем по увеличению высоты. Если высоты зданий одинаковы, то
сортируем по увеличению стоимости.
int cmp(Building a, Building b)
{
if (a.h == b.h)
return a.cost < b.cost;
return a.h < b.h;
}
Функция f вычисляет стоимость, за которую можно сделать все
постройки равными высоте здания номер x.
long long f(int x)
{
long long ret = 0;
for (int i = 1; i <= n; i++)
ret += 1LL * abs(b[x].h - b[i].h) * b[i].cost;
return ret;
}
Функция ternary_search при помощи тернарного поиска ищет такое
x ∈
[left; right], что f(x) минимально. Изначально [left; right] = [1; n].
long long ternarySearch(int left, int right)
{
while (right - left >= 3)
{
int a = left + (right - left) / 3;
int b = left + 2 * (right - left) / 3;
if (f(a) > f(b))
left = a;
else
right = b;
}
Разница между left и right не больше 3. Ищем
минимум f(x) на промежутке
[left; right] полным перебором.
long long res = f(left++);
while (left <= right)
res = min(res, f(left++));
return res;
}
Основная
часть программы. Читаем входные данные.
scanf("%d", &n);
for (i = 1; i <= n; i++)
scanf("%d", &b[i].h);
for (i = 1; i <= n; i++)
scanf("%d", &b[i].cost);
Сортируем
здания.
sort(b + 1,
b + n + 1, cmp);
Вычисляем
и выводим ответ. Здания нумеруются от 1 до n.
printf("%lld\n", ternarySearch(1, n));